home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue35 / eval_dan / EVAL_DAN.ZIP / Mathcomp.~pa next >
Encoding:
Text File  |  1997-12-30  |  42.6 KB  |  1,597 lines

  1. unit mathcomp;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  7.  
  8. type
  9.   TVector2D = record
  10.     x,y: double;
  11.   end;
  12.  
  13.   TVector3D = record
  14.     X,Y,Z: Double;
  15.   end;
  16.  
  17.   TTokenType = (ttUnknown,ttOperation,ttVariable,ttConstant);
  18.  
  19.   //TVariableList
  20.   PVariableRecord = ^TVariableRecord;
  21.   TVariableRecord = record
  22.     VarData: Double;
  23.     VarName: String;
  24.   end;
  25.  
  26.   //Forward declarations
  27.   TExpressionTree = class;
  28.  
  29.   TVarList = class(TList)
  30.   private
  31.     function GetVars(Index: String): PVariableRecord;
  32.   public
  33.     property Vars[Index: String]: PVariableRecord read GetVars;
  34.     //Methods
  35.     destructor Destroy; override;
  36.     function GetIndex(AValue: String): Integer;
  37.     function NewVar(AName: String; AData: Double): PVariableRecord;
  38.   end;
  39.  
  40.   TExpressionNode = class(TObject)
  41.   private
  42.     FValue: String;
  43.     FParent: TExpressionNode;
  44.     FTokenType: TTokenType;
  45.     FChildren: TList;
  46.     FValidValue: Boolean;
  47.     FNumValue: Double;
  48.     FVarPointer: PVariableRecord;
  49.     FTree: TExpressionTree;
  50.   public
  51.     property Value: String read FValue write FValue;
  52.     property Parent: TExpressionNode read FParent write FParent;
  53.     property TokenType: TTokenType read FTokenType write FTokenType;
  54.     property Children: TList read FChildren write FChildren;
  55.     property ValidValue: Boolean read FValidValue write FValidValue;
  56.     property NumValue: Double read FNumValue write FNumValue;
  57.     property VarPointer: PVariableRecord read FVarPointer write FVarPointer;
  58.     property Tree: TExpressionTree read FTree write FTree;
  59.     //Methods
  60.     function CreateChild: TExpressionNode;
  61.     function Evaluate(SuppressErrors,UseVars: Boolean): Double;
  62.     constructor Create(AOwner: TExpressionNode; ATree: TExpressionTree);
  63.     destructor Destroy; override;
  64.   end;
  65.  
  66.   TExpressionTree = class(TPersistent)
  67.   private
  68.     FTopNode: TExpressionNode;
  69.     FExpression: String;
  70.     FCheckSyntax: Boolean;
  71.     FTokens: TStringList;
  72.     FVarList: TVarList;
  73.     procedure SetExpression(AValue: String);
  74.   public
  75.     property TopNode: TExpressionNode read FTopNode write FTopNode;
  76.     property Expression: String read FExpression write SetExpression;
  77.     property CheckSyntax: Boolean read FCheckSyntax write FCheckSyntax;
  78.     property Tokens: TStringList read FTokens write FTokens;
  79.     property VarList: TVarList read FVarList write FVarList;
  80.     //Methods
  81.     constructor Create;
  82.     destructor Destroy; override;
  83.     procedure MakeTokens;
  84.     procedure RemoveBadTokens;
  85.   end;
  86.  
  87.   TDataSet2D = class(TObject)
  88.   private
  89.     FData: pointer;
  90.     FCount: Longint;
  91.     function GetData(Index: Longint): TVector2D;
  92.     procedure SetData(Index: Longint; AValue: TVector2D);
  93.     procedure SetCount(AValue: longint);
  94.   public
  95.     property Data[Index: longint]: TVector2D read GetData write SetData;
  96.     property Count: longint read FCount write SetCount;
  97.     constructor Create(ACount: Longint);
  98.     destructor Destroy; override;
  99.   end;
  100.  
  101.   TDataSet3D = class(TObject)
  102.   private
  103.     FData: pointer;
  104.     FCount: Longint;
  105.     function GetData(Index: Longint): TVector3D;
  106.     procedure SetData(Index: Longint; AValue: TVector3D);
  107.     procedure SetCount(AValue: longint);
  108.   public
  109.     property Data[Index: longint]: TVector3D read GetData write SetData;
  110.     property Count: longint read FCount write SetCount;
  111.     constructor Create(ACount: Longint);
  112.     destructor Destroy; override;
  113.   end;
  114.  
  115.   TDataLabel = class(TObject)
  116.   private
  117.     FData: String;
  118.     Fx,Fy: integer;
  119.   public
  120.     property Data: string read FData write FData;
  121.     property x: integer read Fx write Fx;
  122.     property y: integer read Fy write Fy;
  123.   end;
  124.  
  125.   {TAxesView}
  126.  
  127.   TAxesAlign = (aaPositive,aaNegative);
  128.   TCoord2DFunc = function (InV: TVector2D): TVector2D of Object;
  129.   TCoord3DFunc = function (InV: TVector3D): TVector3D of Object;
  130.  
  131.   TAxesView = class(TCustomControl)
  132.   private
  133.     { Private declarations }
  134.     FXMin,FXMax,FXScale,FYMin,FYMax,FYScale: double;
  135.     FShowGrid,FShowAxes,FShowLabels,FAutoUpdate: Boolean;
  136.     FXAxisColor,FYAxisColor,FGridColor: TColor;
  137.     FOnGetMathCoord,FOnGetRealCoord: TCoord2DFunc;
  138.     FRXScale,FRYScale: Double;
  139.     FOrigin: TVector2D;
  140.     FGrid: TDataSet2D;
  141.     FLabels: TList;
  142.     FDecimals: Integer;
  143.     FAlignLabelX,FAlignLabelY: TAxesAlign;
  144.     FOnPaint: TNotifyEvent;
  145.     procedure SetXMin(AValue: Double);
  146.     procedure SetXMax(AValue: Double);
  147.     procedure SetXScale(AValue: Double);
  148.     procedure SetYMin(AValue: Double);
  149.     procedure SetYMax(AValue: Double);
  150.     procedure SetYScale(AValue: Double);
  151.     procedure SetShowGrid(AValue: Boolean);
  152.     procedure SetShowAxes(AValue: Boolean);
  153.     procedure SetShowLabels(AValue: Boolean);
  154.     procedure SetXAxisColor(AValue: TColor);
  155.     procedure SetYAxisColor(AValue: TColor);
  156.     procedure SetGridColor(AValue: TColor);
  157.     procedure SetAlignLabelX(AValue: TAxesAlign);
  158.     procedure SetAlignLabelY(AValue: TAxesAlign);
  159.     procedure SetDecimals(AValue: Integer);
  160.     procedure FontChange(Sender: TObject); virtual;
  161.     //inherited methods
  162.   protected
  163.     { Protected declarations }
  164.     procedure DrawAxes; virtual;
  165.     procedure DrawGrid; virtual;
  166.     procedure DrawLabels; virtual;
  167.   public
  168.     { Public declarations }
  169.     property Labels: TList read FLabels write FLabels;
  170.     property RXScale: double read FRXScale;
  171.     property RYScale: double read FRYScale;
  172.     property Origin: TVector2D read FOrigin;
  173.     property Grid: TDataSet2D read FGrid;
  174.     //Methods
  175.     procedure DoAutoPan(X,Y: Integer); virtual;
  176.     procedure Zoom(Percent: Integer);
  177.     procedure SetScale(AXMin,AXMax,AXScale,AYMin,AYMax,AYScale: Double);
  178.     function GetMathCoord(InV: TVector2D): TVector2D; virtual;
  179.     function GetRealCoord(InV: TVector2D): TVector2D; virtual;
  180.     procedure RecalcScale; virtual;
  181.     constructor Create(AOwner: TComponent); override;
  182.     destructor Destroy; override;
  183.     procedure Paint; override;
  184.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  185.   published
  186.     { Published declarations }
  187.     property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate;
  188.     property AlignLabelX: TAxesAlign read FAlignLabelX write SetAlignLabelX;
  189.     property AlignLabelY: TAxesAlign read FAlignLabelY write SetAlignLabelY;
  190.     property XMin: double read FXMin write SetXMin;
  191.     property XMax: double read FXMax write SetXMax;
  192.     property XScale: double read FXScale write SetXScale;
  193.     property YMin: double read FYMin write SetYMin;
  194.     property YMax: double read FYMax write SetYMax;
  195.     property YScale: double read FYScale write SetYScale;
  196.     property ShowGrid: Boolean read FShowGrid write SetShowGrid;
  197.     property ShowAxes: Boolean read FShowAxes write SetShowAxes;
  198.     property ShowLabels: Boolean read FShowLabels write SetShowLabels;
  199.     property XAxisColor: TColor read FXAxisColor write SetXAxisColor;
  200.     property YAxisColor: TColor read FYAxisColor write SetYAxisColor;
  201.     property GridColor: TColor read FGridColor write SetGridColor;
  202.     property Decimals: Integer read FDecimals write SetDecimals;
  203.     //Inherited properties to be published
  204.     property Color;
  205.     property Font;
  206.     property Align;
  207.     //Events
  208.     property OnGetMathCoord: TCoord2DFunc read FOnGetMathCoord write FOnGetMathCoord;
  209.     property OnGetRealCoord: TCoord2DFunc read FOnGetRealCoord write FOnGetRealCoord;
  210.     property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
  211.     //Inherited events to be published
  212.     property OnEnter;
  213.     property OnExit;
  214.     property OnDblClick;
  215.     property OnDragDrop;
  216.     property OnDragOver;
  217.     property OnEndDrag;
  218.     property OnMouseDown;
  219.     property OnMouseMove;
  220.     property OnMouseUp;
  221.     property OnStartDrag;
  222.   end;
  223.  
  224. const
  225.   ValidOps = ['+','-','*','/',')','(','^','='];
  226.  
  227. procedure Register;
  228. function V2D(x,y: double): TVector2D;
  229. function V3D(vx,vy,vz: double): TVector3D;
  230. function V2D2Point(V: TVector2D): TPoint;
  231. function V3DXY(V: TVector3D): TVector2D;
  232. function V3DXZ(V: TVector3D): TVector2D;
  233. function V3DZY(V: TVector3D): TVector2D;
  234. function V3D2STR(V: TVector3D): String;
  235.  
  236. implementation
  237.  
  238. //-----Global routines-----//
  239.  
  240. function V3D(vx,vy,vz: double): TVector3D;
  241. begin
  242.   with Result do
  243.   begin
  244.     X := vx;
  245.     Y := vy;
  246.     Z := vz;
  247.   end;
  248. end;
  249.  
  250. function V3DXY(V: TVector3D): TVector2D;
  251. begin
  252.   with Result do
  253.   begin
  254.     x := V.x;
  255.     y := V.y;
  256.   end;
  257. end;
  258.  
  259. function V3DXZ(V: TVector3D): TVector2D;
  260. begin
  261.   with Result do
  262.   begin
  263.     x := V.x;
  264.     y := V.z;
  265.   end;
  266. end;
  267.  
  268. function V3DZY(V: TVector3D): TVector2D;
  269. begin
  270.   with Result do
  271.   begin
  272.     x := V.z;
  273.     y := V.y;
  274.   end;
  275. end;
  276.  
  277. function V3D2STR(V: TVector3D): String;
  278. var
  279. SX,SY,SZ: String;
  280. begin
  281.   Str(V.x,SX);
  282.   Str(V.y,SY);
  283.   Str(V.z,SZ);
  284.   Result := '<'+SX+','+SY+','+SZ+'>';
  285. end;
  286.  
  287. function V2D(x,y: double): TVector2D;
  288. var
  289. AResult: TVector2D;
  290. begin
  291.   AResult.x := x;
  292.   AResult.y := y;
  293.   Result := AResult;
  294. end;
  295.  
  296. function V2D2Point(V: TVector2D): TPoint;
  297. begin
  298.   with Result do
  299.   begin
  300.     x := Round(V.x);
  301.     y := Round(V.y);
  302.   end;
  303. end;
  304.  
  305. procedure Register;
  306. begin
  307.   RegisterComponents('Custom', [TAxesView]);
  308. end;
  309.  
  310. //-----TVarList implementation-----//
  311.  
  312. function TVarList.GetIndex(AValue: String): Integer;
  313. var
  314. i: integer;
  315. begin
  316.   if Count>0 then
  317.   begin
  318.     for i := 0 to Count-1 do
  319.     begin
  320.       if PVariableRecord(items[i])^.VarName = AValue then
  321.       begin
  322.         Result := i;
  323.         Exit;
  324.       end;
  325.     end;
  326.   end;
  327.   //Nothing found--return -1 as error code
  328.   Result := -1;
  329. end;
  330.  
  331. function TVarList.GetVars(Index: String): PVariableRecord;
  332. var
  333. ti: integer;
  334. begin
  335.   ti := GetIndex(Index);
  336.   if ti > -1 then
  337.     Result := PVariableRecord(Items[ti])
  338.   else
  339.     Result := nil;
  340. end;
  341.  
  342. function TVarList.NewVar(AName: String; AData: Double): PVariableRecord;
  343. var
  344. VarRec: PVariableRecord;
  345. ti: integer;
  346. begin
  347.   ti := GetIndex(AName);
  348.   if ti = -1 then
  349.   begin
  350.     VarRec := New(PVariableRecord);
  351.     VarRec^.VarName := AName;
  352.     VarRec^.VarData := AData;
  353.     Add(VarRec);
  354.   end
  355.   else
  356.   begin
  357.     VarRec := PVariableRecord(Items[ti]);
  358.     VarRec^.VarData := AData;
  359.   end;
  360.   Result := VarRec;
  361. end;
  362.  
  363. destructor TVarList.Destroy;
  364. begin
  365.   while Count>0 do
  366.   begin
  367.     Dispose(Items[0]);
  368.     Delete(0);
  369.   end;
  370.   inherited Destroy;
  371. end;
  372.  
  373. //-----TExpressionNode implementation-----//
  374.  
  375. constructor TExpressionNode.Create(AOwner: TExpressionNode;
  376. ATree: TExpressionTree);
  377. begin
  378.   inherited Create;
  379.   FParent := AOwner;
  380.   FTree := ATree;
  381.   FChildren := TList.Create;
  382.   FValidValue := False;
  383. end;
  384.  
  385. destructor TExpressionNode.Destroy;
  386. begin
  387.   while FChildren.Count > 0 do
  388.   begin
  389.     TExpressionNode(FChildren.items[0]).Free;
  390.     FChildren.Delete(0);
  391.   end;
  392.   FChildren.Free;
  393.   inherited Destroy;
  394. end;
  395.  
  396. function TExpressionNode.CreateChild: TExpressionNode;
  397. var
  398. tNode: TExpressionNode;
  399. begin
  400.   tNode := TExpressionNode.Create(Self,Tree);
  401.   Children.Add(tNode);
  402.   Result := tNode;
  403. end;
  404.  
  405. function TExpressionNode.Evaluate(SuppressErrors,UseVars: Boolean): Double;
  406. var
  407. tf: double;
  408. i: longint;
  409. invop: boolean;
  410. begin
  411.   //Evaluate the children first
  412.   if Children.Count>0 then
  413.   begin
  414.     for i := 0 to Children.Count-1 do
  415.       TExpressionNode(Children.items[i]).Evaluate(SuppressErrors,UseVars);
  416.   end;
  417.   //Now that children are evaluated, do this node
  418.   case TokenType of
  419.     ttUnknown:
  420.     begin
  421.       //This hasn't been trimmed so just evaluate the first child
  422.       if Children.Count > 0 then
  423.       begin
  424.         NumValue := TExpressionNode(Children.items[0]).
  425.         Evaluate(SuppressErrors,UseVars);
  426.         ValidValue := TExpressionNode(Children.items[0]).ValidValue;
  427.         Result := NumValue;
  428.       end
  429.       else
  430.       begin
  431.         if not SuppressErrors then
  432.         begin
  433.           ShowMessage('Error in evaluation tree: ttUnknown node with no children.');
  434.           Exit;
  435.         end;
  436.       end;
  437.     end;
  438.     ttConstant:
  439.     begin
  440.       if not ValidValue then
  441.       begin
  442.         //Store everything as floats for now
  443.         try
  444.           tf := StrToFloat(Value);
  445.           //Ok, it's a valid float value so store it
  446.           NumValue := tf;
  447.           ValidValue := True;
  448.         except
  449.           //It's not a valid numeric constant!
  450.           on EConvertError do
  451.           begin
  452.             if not SuppressErrors then
  453.             begin
  454.               ShowMessage('Invalid numeric constant: '+Value);
  455.               Exit;
  456.             end;
  457.           end;
  458.         end;
  459.       end;
  460.       Result := NumValue;
  461.     end;
  462.     ttVariable:
  463.     begin
  464.       if UseVars then
  465.       begin
  466.         //Make sure variable hasn't changed from token
  467.         if not Assigned(VarPointer) or (VarPointer^.VarName <> Value) then
  468.         begin
  469.           //Find new variable or create one if needed
  470.           VarPointer := Tree.VarList.Vars[Value];
  471.           if VarPointer = nil then
  472.             VarPointer := Tree.VarList.NewVar(Value,0);
  473.         end;
  474.         //Variable is now valid
  475.         NumValue := VarPointer^.VarData;
  476.         ValidValue := True;
  477.       end
  478.       else
  479.         ValidValue := False;
  480.     end;
  481.     ttOperation:
  482.     begin
  483.       //This is where the math takes place
  484.       ValidValue := false;
  485.       invop := true;
  486.       if Value = '+' then
  487.       begin
  488.         if Children.Count = 2 then
  489.         begin
  490.           NumValue := TExpressionNode(Children.items[0]).NumValue+
  491.           TExpressionNode(Children.items[1]).NumValue;
  492.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  493.           TExpressionNode(Children.items[1]).ValidValue;
  494.           invop := false;
  495.         end
  496.         else
  497.         begin
  498.           ValidValue := False;
  499.           if not SuppressErrors then
  500.           begin
  501.             ShowMessage('Error: addition operation with '+
  502.             IntToStr(Children.Count)+' values.');
  503.             Exit;
  504.           end;
  505.         end;
  506.       end;
  507.       if Value = '-' then
  508.       begin
  509.         if Children.Count = 2 then
  510.         begin
  511.           NumValue := TExpressionNode(Children.items[0]).NumValue-
  512.           TExpressionNode(Children.items[1]).NumValue;
  513.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  514.           TExpressionNode(Children.items[1]).ValidValue;
  515.           invop := false;
  516.         end
  517.         else
  518.         begin
  519.           ValidValue := False;
  520.           if not SuppressErrors then
  521.           begin
  522.             ShowMessage('Error: subtraction operation with '+
  523.             IntToStr(Children.Count)+' values.');
  524.             Exit;
  525.           end;
  526.         end;
  527.       end;
  528.       if Value = '*' then
  529.       begin
  530.         if Children.Count = 2 then
  531.         begin
  532.           NumValue := TExpressionNode(Children.items[0]).NumValue*
  533.           TExpressionNode(Children.items[1]).NumValue;
  534.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  535.           TExpressionNode(Children.items[1]).ValidValue;
  536.           invop := false;
  537.         end
  538.         else
  539.         begin
  540.           ValidValue := False;
  541.           if not SuppressErrors then
  542.           begin
  543.             ShowMessage('Error: multiplacation operation with '+
  544.             IntToStr(Children.Count)+' values.');
  545.             Exit;
  546.           end;
  547.         end;
  548.       end;
  549.       if Value = '/' then
  550.       begin
  551.         if Children.Count = 2 then
  552.         begin
  553.           NumValue := TExpressionNode(Children.items[0]).NumValue/
  554.           TExpressionNode(Children.items[1]).NumValue;
  555.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  556.           TExpressionNode(Children.items[1]).ValidValue;
  557.           invop := false;
  558.         end
  559.         else
  560.         begin
  561.           ValidValue := False;
  562.           if not SuppressErrors then
  563.           begin
  564.             ShowMessage('Error: division operation with '+
  565.             IntToStr(Children.Count)+' values.');
  566.             Exit;
  567.           end;
  568.         end;
  569.       end;
  570.       if Value = 'div' then
  571.       begin
  572.         if Children.Count = 2 then
  573.         begin
  574.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue/
  575.           TExpressionNode(Children.items[1]).NumValue);
  576.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  577.           TExpressionNode(Children.items[1]).ValidValue;
  578.           invop := false;
  579.         end
  580.         else
  581.         begin
  582.           ValidValue := False;
  583.           if not SuppressErrors then
  584.           begin
  585.             ShowMessage('Error: integer division operation with '+
  586.             IntToStr(Children.Count)+' values.');
  587.             Exit;
  588.           end;
  589.         end;
  590.       end;
  591.       if Value = 'mod' then
  592.       begin
  593.         if Children.Count = 2 then
  594.         begin
  595.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) mod
  596.           Round(TExpressionNode(Children.items[1]).NumValue);
  597.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  598.           TExpressionNode(Children.items[1]).ValidValue;
  599.           invop := false;
  600.         end
  601.         else
  602.         begin
  603.           ValidValue := False;
  604.           if not SuppressErrors then
  605.           begin
  606.             ShowMessage('Error: modulo operation with '+
  607.             IntToStr(Children.Count)+' values.');
  608.             Exit;
  609.           end;
  610.         end;
  611.       end;
  612.       if Value = 'and' then
  613.       begin
  614.         if Children.Count = 2 then
  615.         begin
  616.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) and
  617.           Round(TExpressionNode(Children.items[1]).NumValue);
  618.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  619.           TExpressionNode(Children.items[1]).ValidValue;
  620.           invop := false;
  621.         end
  622.         else
  623.         begin
  624.           ValidValue := False;
  625.           if not SuppressErrors then
  626.           begin
  627.             ShowMessage('Error: and operation with '+
  628.             IntToStr(Children.Count)+' values.');
  629.             Exit;
  630.           end;
  631.         end;
  632.       end;
  633.       if Value = 'or' then
  634.       begin
  635.         if Children.Count = 2 then
  636.         begin
  637.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) or
  638.           Round(TExpressionNode(Children.items[1]).NumValue);
  639.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  640.           TExpressionNode(Children.items[1]).ValidValue;
  641.           invop := false;
  642.         end
  643.         else
  644.         begin
  645.           ValidValue := False;
  646.           if not SuppressErrors then
  647.           begin
  648.             ShowMessage('Error: or operation with '+
  649.             IntToStr(Children.Count)+' values.');
  650.             Exit;
  651.           end;
  652.         end;
  653.       end;
  654.       if Value = 'xor' then
  655.       begin
  656.         if Children.Count = 2 then
  657.         begin
  658.           NumValue := Round(TExpressionNode(Children.items[0]).NumValue) xor
  659.           Round(TExpressionNode(Children.items[1]).NumValue);
  660.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  661.           TExpressionNode(Children.items[1]).ValidValue;
  662.           invop := false;
  663.         end
  664.         else
  665.         begin
  666.           ValidValue := False;
  667.           if not SuppressErrors then
  668.           begin
  669.             ShowMessage('Error: addition operation with '+
  670.             IntToStr(Children.Count)+' values.');
  671.             Exit;
  672.           end;
  673.         end;
  674.       end;
  675.       if Value = '=' then
  676.       begin
  677.         if Children.Count = 2 then
  678.         begin
  679.           NumValue := Ord(TExpressionNode(Children.items[0]).NumValue=
  680.           TExpressionNode(Children.items[1]).NumValue);
  681.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  682.           TExpressionNode(Children.items[1]).ValidValue;
  683.           invop := false;
  684.         end
  685.         else
  686.         begin
  687.           ValidValue := False;
  688.           if not SuppressErrors then
  689.           begin
  690.             ShowMessage('Error: equative operation with '+
  691.             IntToStr(Children.Count)+' values.');
  692.             Exit;
  693.           end;
  694.         end;
  695.       end;
  696.       if Value = '^' then
  697.       begin
  698.         if Children.Count = 2 then
  699.         begin
  700.           NumValue := Exp(TExpressionNode(Children.items[1]).NumValue *
  701.           Ln(TExpressionNode(Children.items[0]).NumValue));
  702.           ValidValue := TExpressionNode(Children.items[0]).ValidValue and
  703.           TExpressionNode(Children.items[1]).ValidValue;
  704.           invop := false;
  705.         end
  706.         else
  707.         begin
  708.           ValidValue := False;
  709.           if not SuppressErrors then
  710.           begin
  711.             ShowMessage('Error: exponential operation with '+
  712.             IntToStr(Children.Count)+' values.');
  713.             Exit;
  714.           end;
  715.         end;
  716.         if invop then
  717.         begin
  718.           if not SuppressErrors then
  719.             ShowMessage('Error: invalid operation '+Value);
  720.         end
  721.       end;
  722.     end;
  723.   end;
  724.   Result := NumValue;
  725. end;
  726.  
  727.  
  728.  
  729. //-----TExpressionTree implementation-----//
  730.  
  731. constructor TExpressionTree.Create;
  732. begin
  733.   inherited Create;
  734.   FCheckSyntax := True;
  735.   FTokens := TStringList.Create;
  736.   FVarList := TVarList.Create;
  737. end;
  738.  
  739. destructor TExpressionTree.Destroy;
  740. begin
  741.   if Assigned(FTopNode) then
  742.     FTopNode.Free;
  743.   FVarList.Free;
  744.   FTokens.Free;
  745.   inherited Destroy;
  746. end;
  747.  
  748. procedure TExpressionTree.RemoveBadTokens;
  749. var
  750. i: longint;
  751. begin
  752.   if Tokens.Count > 0 then
  753.   begin
  754.     //Cut out extra parentheses.
  755.     i := 1;
  756.     repeat
  757.       if (Tokens[i-1] = '(') and (Tokens[i+1] = ')') then
  758.       begin
  759.         //No need for parentheses around a single token
  760.         Tokens.Delete(i-1);
  761.         Tokens.Delete(i);
  762.         i := 1;
  763.       end;
  764.       Inc(i);
  765.     until (i>(Tokens.Count-2))
  766.   end;
  767. end;
  768.  
  769. procedure TExpressionTree.MakeTokens;
  770. var
  771. incount,start: longint;
  772. begin
  773.   Tokens.Clear;
  774.   incount := 1;
  775.   start := 1;
  776.   repeat
  777.     //Read new token until we find a valid operation char or a space
  778.     while not (FExpression[incount] in ValidOps)
  779.     and not (FExpression[incount] = ' ') do
  780.     begin
  781.       //It's still a valid token so keep reading
  782.       Inc(incount);
  783.       if (incount>Length(FExpression)) then
  784.       begin
  785.         //We've gone past the end of the string
  786.         //Write the token and exit
  787.         Tokens.Add(Copy(FExpression,start,incount-start));
  788.         Exit;
  789.       end;
  790.     end;
  791.     //We've found a valid operation or space character
  792.     //Record token before operation or space
  793.     if (incount-start)>0 then
  794.       Tokens.Add(Copy(FExpression,start,incount-start));
  795.     //Record an operation, but discard a space
  796.     if FExpression[incount] in ValidOps then
  797.       Tokens.Add(Copy(FExpression,incount,1));
  798.     start := incount+1;
  799.     incount := start;
  800.   until (start>Length(FExpression));
  801. end;
  802.  
  803. procedure TExpressionTree.SetExpression(AValue: String);
  804. var
  805. i,c: longint;
  806. CNode,tNode: TExpressionNode;
  807. CToken: String;
  808. tf: double;
  809.  
  810. function IsLowerOp: Boolean;
  811. begin
  812.   Result := (CToken='+') or (CToken='-') or (CToken='=') or (CToken='or') or
  813.   (CToken='and') or (CToken='xor');
  814. end;
  815.  
  816. function IsMiddleOp: Boolean;
  817. begin
  818.   Result := (CToken='*') or (CToken='/') or (CToken='div') or (CToken='mod');
  819. end;
  820.  
  821. begin
  822.   if (AValue<>FExpression) and (AValue <> '') then
  823.   begin
  824.     if CheckSyntax then
  825.     begin
  826.       c := 0;
  827.       for i := 1 to Length(AValue) do
  828.       begin
  829.         case AValue[i] of
  830.           '(': Inc(c);
  831.           ')': Dec(c);
  832.         end;
  833.       end;
  834.       if (c<>0) then
  835.       begin
  836.         ShowMessage('Error in syntax: parentheses unbalanced at '+IntToStr(c));
  837.         Exit;
  838.       end;
  839.     end;
  840.     //No syntax errors found yet--set property and clear old tree
  841.     FExpression := AValue;
  842.     if Assigned(FTopNode) then
  843.       FTopNode.Free;
  844.     FTopNode := TExpressionNode.Create(nil,Self);
  845.     //Parse expression so it's ready for tree generation
  846.     MakeTokens;
  847.     //Remove any tokens that are useless or will cause undesired behavior
  848.     RemoveBadTokens;
  849.     //Let's make the tree
  850.     if Tokens.Count>0 then
  851.     begin
  852.       CNode := FTopNode;
  853.       for i := 0 to Tokens.Count-1 do
  854.       begin
  855.         CToken := Tokens.strings[i];
  856.         if CToken='(' then
  857.         begin
  858.           CNode := CNode.CreateChild;
  859.           //Create temporary token for reference of order-of-operations code
  860.           CNode.Value := '(';
  861.           CNode.TokenType := ttOperation;
  862.           CNode := CNode.CreateChild;
  863.           Continue;
  864.         end;
  865.         if IsLowerOp or (Assigned(CNode.Parent) and (CNode.Parent.Value='^')
  866.         and IsMiddleOp) then
  867.         begin
  868.           //Low priority or after an exponent--go up the tree
  869.           if not Assigned(CNode.Parent) then
  870.           begin
  871.             ShowMessage('Error in expression: '+FExpression);
  872.             Exit;
  873.           end;
  874.           repeat
  875.             CNode := CNode.Parent;
  876.           until  not Assigned(CNode.Parent) or
  877.           (CNode.TokenType<>ttOperation) or (CNode.Parent.Value = '(');
  878.           if CNode.TokenType = ttOperation then
  879.           begin
  880.             //Create a new higher level node in-between CNode and CNode.Parent
  881.             //If CNode.Parent is nil then we must setup a new TopNode field
  882.             if not Assigned(CNode.Parent) then
  883.             begin
  884.               if not (CNode = FTopNode) then
  885.               begin
  886.                 ShowMessage('Expression Evaluator Error: '+
  887.                 'Node with nil parent is not top node!');
  888.                 Exit;
  889.               end;
  890.               FTopNode := TExpressionNode.Create(nil,Self);
  891.               FTopNode.Children.Add(CNode);
  892.               CNode.Parent := FTopNode;
  893.             end
  894.             else
  895.             begin
  896.               //Otherwise just insert the new node
  897.               tNode := TExpressionNode.Create(CNode.Parent,Self);
  898.               tNode.Children.Add(CNode);
  899.               //Don't forget to reset children of Parent node
  900.               CNode.Parent.Children.Remove(CNode);
  901.               CNode.Parent.Children.Add(tNode);
  902.               CNode.Parent := tNode;
  903.             end;
  904.           end
  905.           else
  906.           begin
  907.             //There is no operation at this node currently--replace the node
  908.             //data for this operation and continue loop
  909.             CNode.TokenType := ttOperation;
  910.             CNode.Value := CToken;
  911.             Continue;
  912.           end;
  913.           //Node inserted--set current node to parent so that operation can
  914.           //be inserted
  915.           CNode := CNode.Parent;
  916.           CNode.TokenType := ttOperation;
  917.           CNode.Value := CToken;
  918.           Continue;
  919.         end;
  920.         if IsMiddleOp or (CToken='^') then
  921.         begin
  922.           //Middle operation that isn't past an exponent or an exponent--go down
  923.           if not Assigned(CNode.Parent) then
  924.           begin
  925.             ShowMessage('Error in expression: '+FExpression);
  926.             Exit;
  927.           end;
  928.           if CNode.Parent.TokenType = ttOperation then
  929.           begin
  930.             //Insert node before CNode
  931.             tNode := TExpressionNode.Create(CNode,Self);
  932.             while (CNode.Children.Count>0) do
  933.             begin
  934.               TExpressionNode(CNode.Children.items[0]).Parent := tNode;
  935.               tNode.Children.Add(CNode.Children.items[0]);
  936.               CNode.Children.Delete(0);
  937.             end;
  938.             tNode.Value := CNode.Value;
  939.             tNode.TokenType := CNode.TokenType;
  940.             CNode.Children.Add(tNode);
  941.           end
  942.           else
  943.             CNode := CNode.Parent;
  944.           CNode.TokenType := ttOperation;
  945.           CNode.Value := CToken;
  946.           Continue;
  947.         end;
  948.         if CToken = ')' then
  949.         begin
  950.           //We need to backtrack through tree to find our origin--
  951.           {while Assigned(CNode.Parent)
  952.           and (CNode.Parent.TokenType<>ttUnknown) do CNode := CNode.Parent;}
  953.           //Look for '(' marker
  954.           repeat
  955.             CNode := CNode.Parent;
  956.           until (CNode.Parent.Value = '(');
  957.           //Delete the marker and setup CNode
  958.           tNode := CNode;
  959.           CNode := tNode.Parent;
  960.           CNode.Parent.Children.Remove(CNode);
  961.           while (CNode.Children.Count>0) do
  962.           begin
  963.             TExpressionNode(CNode.Children.items[0]).Parent := CNode.Parent;
  964.             CNode.Parent.Children.Add(CNode.Children.items[0]);
  965.             CNode.Children.Delete(0);
  966.           end;
  967.           CNode.Free;
  968.           CNode := tNode;
  969.           //Check to see if TopNode is already assigned and if so insert a new
  970.           //node above it--assuming we're at the TopNode
  971.           if not Assigned(CNode.Parent) then
  972.           begin
  973.             if not (CNode = FTopNode) then
  974.             begin
  975.               ShowMessage('Expression Evaluator Error: '+
  976.               'Node with nil parent is not top node!');
  977.               Exit;
  978.             end;
  979.             //Create new top node
  980.             FTopNode := TExpressionNode.Create(nil,Self);
  981.             FTopNode.Children.Add(CNode);
  982.             CNode.Parent := FTopNode;
  983.           end;
  984.           Continue;
  985.         end;
  986.         //It's not a symbol or an operator, so it must be something else
  987.         //Check to see if it's a valid numeric constant
  988.         try
  989.           tf := StrToFloat(CToken);
  990.           //It's a valid constant since no exception has been raised
  991.           //Create child node for constant
  992.           CNode := CNode.CreateChild;
  993.           CNode.TokenType := ttConstant;
  994.           CNode.Value := CToken;
  995.         except
  996.           on EConvertError do
  997.           begin
  998.             //It's not a valid number, so let's assume it's a variable
  999.             CNode := CNode.CreateChild;
  1000.             CNode.TokenType := ttVariable;
  1001.             CNode.Value := CToken;
  1002.           end;
  1003.         end;
  1004.         //Continue for loop through tokens
  1005.       end;
  1006.     end;
  1007.   end;
  1008. end;
  1009.  
  1010. //-----TAxesView implementation-----//
  1011.  
  1012. procedure TAxesView.DrawGrid;
  1013. var
  1014. i: longint;
  1015. CVector: TVector2D;
  1016. begin
  1017.   with Canvas do
  1018.   begin
  1019.     Pen.Color := GridColor;
  1020.     Pen.Width := 1;
  1021.     for i := 0 to FGrid.Count-1 do
  1022.     begin
  1023.       CVector := FGrid.Data[i];
  1024.       PenPos := Point(0,Round(CVector.y));
  1025.       LineTo(Width-1,Round(CVector.y));
  1026.       PenPos := Point(Round(CVector.x),0);
  1027.       LineTo(Round(CVector.x),Height-1);
  1028.     end;
  1029.   end;
  1030. end;
  1031.  
  1032. procedure TAxesView.DrawAxes;
  1033. begin
  1034.   with Canvas do
  1035.   begin
  1036.     Pen.Width := 2;
  1037.     Pen.Color := XAxisColor;
  1038.     PenPos := (Point(0,Round(Origin.y)));
  1039.     LineTo(Width-1,Round(Origin.y));
  1040.     Pen.Color := YAxisColor;
  1041.     PenPos := (Point(Round(Origin.x),0));
  1042.     LineTo(Round(Origin.x),Height-1);
  1043.   end;
  1044. end;
  1045.  
  1046. procedure TAxesView.DrawLabels;
  1047. var
  1048. i: longint;
  1049. begin
  1050.   Canvas.Brush.Style := bsClear;
  1051.   if Labels.Count > 0 then
  1052.   begin
  1053.     for i := 0 to Labels.Count-1 do
  1054.     begin
  1055.       with TDataLabel(Labels.items[i]) do
  1056.         Canvas.TextOut(x,y,Data);
  1057.     end;
  1058.   end;
  1059. end;
  1060.  
  1061. procedure TAxesView.Paint;
  1062. begin
  1063.   //Draw grid
  1064.   if ShowGrid then DrawGrid;
  1065.   //Draw axes
  1066.   if ShowAxes then DrawAxes;
  1067.   //Draw labels
  1068.   if ShowLabels then DrawLabels;
  1069.   if Assigned(FOnPaint) then
  1070.     FOnPaint(Self);
  1071. end;
  1072.  
  1073. procedure TAxesView.RecalcScale;
  1074. var
  1075. diffx,diffy,i,k,tv: longint;
  1076. j: double;
  1077. CXMod,CYMod: Integer;
  1078. DL: TDataLabel;
  1079. ts,tsb: string;
  1080. CVector: TVector2D;
  1081.  
  1082. function max(a,b: longint): longint;
  1083. begin
  1084.   if (a>b) then
  1085.     Result := a
  1086.   else
  1087.     Result := b;
  1088. end;
  1089.  
  1090. begin
  1091.   FRXScale := Width/(XMax-XMin);
  1092.   FRYScale := Height/(YMin-YMax);
  1093.   if ShowAxes or ShowGrid or ShowLabels then FOrigin := GetRealCoord(V2D(0,0));
  1094.   if ShowGrid then
  1095.   begin
  1096.     //Prepare for maximum possible allocation
  1097.     FGrid.Count :=
  1098.     abs(Round((XMax-XMin)/XScale))+abs(Round((YMax-YMin)/YScale))*2;
  1099.     diffx := abs(Round(GetRealCoord(V2D(XScale,0)).x-Origin.x));
  1100.     diffy := abs(Round(GetRealCoord(V2D(0,YScale)).y-Origin.y));
  1101.     j := 0;
  1102.     //Do -XY first
  1103.     i := Round(Origin.x);
  1104.     k := Round(Origin.y);
  1105.     repeat
  1106.       i := i - diffx;
  1107.       k := k - diffy;
  1108.       FGrid.Data[Round(j)] := V2D(i,k);
  1109.       j := j + 1;
  1110.     until (i<0)and(k<0);
  1111.     //Do +XY next
  1112.     i := Round(Origin.x);
  1113.     k := Round(Origin.y);
  1114.     repeat
  1115.       i := i + diffx;
  1116.       k := k + diffy;
  1117.       FGrid.Data[Round(j)] := V2D(i,k);
  1118.       j := j + 1;
  1119.     until (i>=Width) and (k>=Height);
  1120.     FGrid.Count := Round(j);
  1121.   end;
  1122.   if ShowLabels then
  1123.   begin
  1124.     //Free old information from Labels list
  1125.     while (Labels.Count > 0) do
  1126.     begin
  1127.       TDataLabel(Labels.items[0]).Free;
  1128.       Labels.Delete(0);
  1129.     end;
  1130.     //Setup variables for scale including spacing
  1131.     CVector := GetRealCoord(V2D(XMin+XScale,YMax-YScale));
  1132.     Str(XMin:0:Decimals,ts);
  1133.     Str(XMax:0:Decimals,tsb);
  1134.     CXMod := Trunc(max(Canvas.TextWidth(ts),
  1135.     Canvas.TextWidth(tsb))*1.05/(CVector.x))+1;
  1136.     Str(YMin:0:Decimals,ts);
  1137.     Str(YMax:0:Decimals,tsb);
  1138.     CYMod := Trunc(max(Canvas.TextHeight(ts),
  1139.     Canvas.TextHeight(tsb))*1.05/(CVector.y))+1;
  1140.     //Store the actual labels
  1141.     //Do X- first
  1142.     j := -(CXMod*XScale);
  1143.     repeat
  1144.       DL := TDataLabel.Create;
  1145.       Str(j:0:Decimals,ts);
  1146.       DL.Data := ts;
  1147.       tv := Round(GetRealCoord(V2D(j,0)).x);
  1148.       DL.x := tv-(Canvas.TextWidth(ts) div 2);
  1149.       if (AlignLabelX = aaNegative) then
  1150.         DL.y := Round(Origin.y) + 1
  1151.       else
  1152.         DL.y := Round(Origin.y)-Canvas.TextHeight(ts)-1;
  1153.       Labels.Add(DL);
  1154.       j := j - (CXMod*XScale);
  1155.     until (j < XMin);
  1156.     //Do X+ now
  1157.     j := (CXMod*XScale);
  1158.     repeat
  1159.       DL := TDataLabel.Create;
  1160.       Str(j:0:Decimals,ts);
  1161.       DL.Data := ts;
  1162.       tv := Round(GetRealCoord(V2D(j,0)).x);
  1163.       DL.x := tv-(Canvas.TextWidth(ts) div 2);
  1164.       if (AlignLabelX = aaNegative) then
  1165.         DL.y := Round(Origin.y) + 1
  1166.       else
  1167.         DL.y := Round(Origin.y)-Canvas.TextHeight(ts)-1;
  1168.       Labels.Add(DL);
  1169.       j := j + (CXMod*XScale);
  1170.     until (j > XMax);
  1171.     //Do Y- now
  1172.     j := -(CYMod*YScale);
  1173.     repeat
  1174.       DL := TDataLabel.Create;
  1175.       Str(j:0:Decimals,ts);
  1176.       DL.Data := ts;
  1177.       tv := Round(GetRealCoord(V2D(0,j)).y);
  1178.       if (AlignLabelY = aaNegative) then
  1179.         DL.x := Round(Origin.X)-Canvas.TextWidth(ts)-1
  1180.       else
  1181.         DL.x := Round(Origin.X)+1;
  1182.       DL.y := tv-(Canvas.TextHeight(ts) div 2);
  1183.       Labels.Add(DL);
  1184.       j := j - (CYMod*YScale);
  1185.     until (j < YMin);
  1186.     //Do Y+ now
  1187.     j := (CYMod*YScale);
  1188.     repeat
  1189.       DL := TDataLabel.Create;
  1190.       Str(j:0:Decimals,ts);
  1191.       DL.Data := ts;
  1192.       tv := Round(GetRealCoord(V2D(0,j)).y);
  1193.       if (AlignLabelY = aaNegative) then
  1194.         DL.x := Round(Origin.X)-Canvas.TextWidth(ts)-1
  1195.       else
  1196.         DL.x := Round(Origin.X)+1;
  1197.       DL.y := tv-(Canvas.TextHeight(ts) div 2);
  1198.       Labels.Add(DL);
  1199.       j := j + (CYMod*YScale);
  1200.     until (j > YMax);
  1201.   end;
  1202. end;
  1203.  
  1204. procedure TAxesView.DoAutoPan(X,Y: Integer);
  1205. var
  1206. V: TVector2D;
  1207. begin
  1208.   V := GetMathCoord(V2D(X,Y));
  1209.   if (X<5) then FXMin := FXMin-FXScale
  1210.   else
  1211.   begin
  1212.     if (X>Width-5) then FXMax := FXMax+FXScale
  1213.     else
  1214.     begin
  1215.       if (Y<5) then FYMax := FYMax+FYScale
  1216.       else
  1217.       begin
  1218.         if (Y>Height-5) then FYMin := FYMin-FYScale
  1219.         else
  1220.           Exit;
  1221.       end;
  1222.     end;
  1223.   end;
  1224.   RecalcScale;
  1225.   V := GetRealCoord(V);
  1226.   SetCursorPos(ClientOrigin.X+Round(V.X),ClientOrigin.Y+Round(V.Y));
  1227. end;
  1228.  
  1229. function TAxesView.GetRealCoord(InV: TVector2D): TVector2D;
  1230. begin
  1231.   if Assigned(FOnGetRealCoord) then
  1232.     FOnGetRealCoord(InV);
  1233.   with Result do
  1234.   begin
  1235.     x := RXScale*(InV.x-XMin);
  1236.     y := RYScale*(InV.y-YMax);
  1237.   end;
  1238. end;
  1239.  
  1240. function TAxesView.GetMathCoord(Inv: TVector2D): TVector2D;
  1241. begin
  1242.   with InV do
  1243.   begin
  1244.     x := (x/RXScale)+XMin;
  1245.     y := (y/RYScale)+YMax;
  1246.   end;
  1247.   if Assigned(OnGetMathCoord) then
  1248.     FOnGetMathCoord(InV);
  1249.   Result := InV;
  1250. end;
  1251.  
  1252. procedure TAxesView.Zoom(Percent: Integer);
  1253. begin
  1254.   if Percent>0 then
  1255.   begin
  1256.     FXMin := FXMin*(Percent/100);
  1257.     FXMax := FXMax*(Percent/100);
  1258.     FYMin := FYMin*(Percent/100);
  1259.     FYMax := FYMax*(Percent/100);
  1260.     RecalcScale;
  1261.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1262.   end;
  1263. end;
  1264.  
  1265. procedure TAxesView.SetScale(AXMin,AXMax,AXScale,AYMin,AYMax,AYScale: Double);
  1266. begin
  1267.   FXMin := AXMin;
  1268.   FXMax := AXMax;
  1269.   FXScale := AXScale;
  1270.   FYMin := AYMin;
  1271.   FYMax := AYMax;
  1272.   FYScale := AYScale;
  1273.   RecalcScale;
  1274.   if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1275. end;
  1276.  
  1277. constructor TAxesView.Create(AOwner: TComponent);
  1278. begin
  1279.   inherited Create(AOwner);
  1280.   FGrid := TDataSet2D.Create(20);
  1281.   //Setup default values
  1282.   FXMin := -100;
  1283.   FXMax := 100;
  1284.   FXScale := 10;
  1285.   FYMin := -100;
  1286.   FYMax := 100;
  1287.   FYScale := 10;
  1288.   FDecimals := 0;
  1289.   FShowGrid := True;
  1290.   FShowAxes := True;
  1291.   FShowLabels := True;
  1292.   FLabels := TList.Create;
  1293.   FXAxisColor := clBlack;
  1294.   FYAxisColor := clBlack;
  1295.   FGridColor := clSilver;
  1296.   FAutoUpdate := True;
  1297.   Color := clWhite;
  1298.   Width := 200;
  1299.   Height := 200;
  1300.   //Hook events in object
  1301.   Font.OnChange := FontChange;
  1302. end;
  1303.  
  1304. destructor TAxesView.Destroy;
  1305. begin
  1306.   FGrid.Free;
  1307.   inherited Destroy;
  1308. end;
  1309.  
  1310. procedure TAxesView.WMSize(var Message: TWMSize);
  1311. begin
  1312.   if (Message.Width < 50) or (Message.Height < 50) then Exit;
  1313.   inherited;
  1314.   if not (csLoading in ComponentState) then
  1315.   begin
  1316.     RecalcScale;
  1317.     Refresh;
  1318.   end;
  1319. end;
  1320.  
  1321. procedure TAxesView.FontChange(Sender: TObject);
  1322. begin
  1323.   Canvas.Font.Assign(Font);
  1324.   if (csDesigning in ComponentState) or AutoUpdate then
  1325.   begin
  1326.     RecalcScale;
  1327.     Refresh;
  1328.   end;
  1329. end;
  1330.  
  1331. procedure TAxesView.SetDecimals(AValue: Integer);
  1332. begin
  1333.   if (AValue<>FDecimals) and (AValue>=0) and (AValue<9) then
  1334.   begin
  1335.     FDecimals := AValue;
  1336.     if (csDesigning in ComponentState) or AutoUpdate then
  1337.     begin
  1338.       RecalcScale;
  1339.       Refresh;
  1340.     end;
  1341.   end;
  1342. end;
  1343.  
  1344. procedure TAxesView.SetXMin(AValue: Double);
  1345. begin
  1346.   if (AValue <> FXMin) and (AValue < FXMax) then
  1347.   begin
  1348.     FXMin := AValue;
  1349.     if (csDesigning in ComponentState) or AutoUpdate then
  1350.     begin
  1351.       RecalcScale;
  1352.       Refresh;
  1353.     end;
  1354.   end;
  1355. end;
  1356.  
  1357. procedure TAxesView.SetXMax(AValue: Double);
  1358. begin
  1359.   if (AValue <> FXMax) and (AValue > FXMin) then
  1360.   begin
  1361.     FXMax := AValue;
  1362.     if (csDesigning in ComponentState) or AutoUpdate then
  1363.     begin
  1364.       RecalcScale;
  1365.       Refresh;
  1366.     end;
  1367.   end;
  1368. end;
  1369.  
  1370. procedure TAxesView.SetXScale(AValue: Double);
  1371. begin
  1372.   if AValue <> FXScale then
  1373.   begin
  1374.     FXScale := AValue;
  1375.     if (csDesigning in ComponentState) or AutoUpdate then
  1376.     begin
  1377.       RecalcScale;
  1378.       Refresh;
  1379.     end;
  1380.   end;
  1381. end;
  1382.  
  1383. procedure TAxesView.SetYMin(AValue: Double);
  1384. begin
  1385.   if (AValue <> FYMin) and (AValue<FYMax) then
  1386.   begin
  1387.     FYMin := AValue;
  1388.     if (csDesigning in ComponentState) or AutoUpdate then
  1389.     begin
  1390.       RecalcScale;
  1391.       Refresh;
  1392.     end;
  1393.   end;
  1394. end;
  1395.  
  1396. procedure TAxesView.SetYMax(AValue: Double);
  1397. begin
  1398.   if (AValue <> FYMax) and (AValue>FYMin) then
  1399.   begin
  1400.     FYMax := AValue;
  1401.     if (csDesigning in ComponentState) or AutoUpdate then
  1402.     begin
  1403.       RecalcScale;
  1404.       Refresh;
  1405.     end;
  1406.   end;
  1407. end;
  1408.  
  1409. procedure TAxesView.SetYScale(AValue: Double);
  1410. begin
  1411.   if AValue <> FYScale then
  1412.   begin
  1413.     FYScale := AValue;
  1414.     if (csDesigning in ComponentState) or AutoUpdate then
  1415.     begin
  1416.       RecalcScale;
  1417.       Refresh;
  1418.     end;
  1419.   end;
  1420. end;
  1421.  
  1422. procedure TAxesView.SetShowGrid(AValue: Boolean);
  1423. begin
  1424.   if AValue <> FShowGrid then
  1425.   begin
  1426.     FShowGrid := AValue;
  1427.     if (csDesigning in ComponentState) or AutoUpdate then
  1428.     begin
  1429.       RecalcScale;
  1430.       Refresh;
  1431.     end;
  1432.   end;
  1433. end;
  1434.  
  1435. procedure TAxesView.SetShowAxes(AValue: Boolean);
  1436. begin
  1437.   if AValue <> FShowAxes then
  1438.   begin
  1439.     FShowAxes := AValue;
  1440.     if (csDesigning in ComponentState) or AutoUpdate then
  1441.     begin
  1442.       RecalcScale;
  1443.       Refresh;
  1444.     end;
  1445.   end;
  1446. end;
  1447.  
  1448. procedure TAxesView.SetAlignLabelX(AValue: TAxesAlign);
  1449. begin
  1450.   if AValue<>FAlignLabelX then
  1451.   begin
  1452.     FAlignLabelX := AValue;
  1453.     if (csDesigning in ComponentState) or AutoUpdate then
  1454.     begin
  1455.       RecalcScale;
  1456.       Refresh;
  1457.     end;
  1458.   end;
  1459. end;
  1460.  
  1461. procedure TAxesView.SetAlignLabelY(AValue: TAxesAlign);
  1462. begin
  1463.   if AValue<>FAlignLabelY then
  1464.   begin
  1465.     FAlignLabelY := AValue;
  1466.     if (csDesigning in ComponentState) or AutoUpdate then
  1467.     begin
  1468.       RecalcScale;
  1469.       Refresh;
  1470.     end;
  1471.   end;
  1472. end;
  1473.  
  1474. procedure TAxesView.SetShowLabels(AValue: Boolean);
  1475. begin
  1476.   if AValue <> FShowLabels then
  1477.   begin
  1478.     FShowLabels := AValue;
  1479.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1480.   end;
  1481. end;
  1482.  
  1483. procedure TAxesView.SetXAxisColor(AValue: TColor);
  1484. begin
  1485.   if AValue <> FXAxisColor then
  1486.   begin
  1487.     FXAxisColor := AValue;
  1488.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1489.   end;
  1490. end;
  1491.  
  1492. procedure TAxesView.SetYAxisColor(AValue: TColor);
  1493. begin
  1494.   if AValue <> FYAxisColor then
  1495.   begin
  1496.     FYAxisColor := AValue;
  1497.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1498.   end;
  1499. end;
  1500.  
  1501. procedure TAxesView.SetGridColor(AValue: TColor);
  1502. begin
  1503.   if AValue <> FGridColor then
  1504.   begin
  1505.     FGridColor := AValue;
  1506.     if (csDesigning in ComponentState) or AutoUpdate then Refresh;
  1507.   end;
  1508. end;
  1509.  
  1510. //-----TDataSet2D implementation-----//
  1511.  
  1512. procedure TDataSet2D.SetData(Index: longint; AValue: TVector2D);
  1513. begin
  1514.   with TVector2D(Ptr(Longint(FData)+(Index*SizeOf(TVector2D)))^) do
  1515.   begin
  1516.     x := AValue.x;
  1517.     y := AValue.y;
  1518.   end;
  1519. end;
  1520.  
  1521. function TDataSet2D.GetData(Index: longint): TVector2D;
  1522. begin
  1523.   with TVector2D(Ptr(Longint(FData)+(Index*SizeOf(TVector2D)))^) do
  1524.   begin
  1525.     Result.x := x;
  1526.     Result.y := y;
  1527.   end;
  1528. end;
  1529.  
  1530. procedure TDataSet2D.SetCount(AValue: longint);
  1531. begin
  1532.   if AValue <> FCount then
  1533.   begin
  1534.     FCount := AValue;
  1535.     ReAllocMem(FData,AValue*SizeOf(TVector2D));
  1536.   end;
  1537. end;
  1538.  
  1539. constructor TDataSet2D.Create(ACount: longint);
  1540. begin
  1541.   inherited Create;
  1542.   FCount := ACount;
  1543.   GetMem(FData,ACount*SizeOf(TVector2D));
  1544. end;
  1545.  
  1546. destructor TDataSet2D.Destroy;
  1547. begin
  1548.   FreeMem(FData,FCount*SizeOf(TVector2D));
  1549.   inherited Destroy;
  1550. end;
  1551.  
  1552. //-----TDataSet3D implementation-----//
  1553.  
  1554. procedure TDataSet3D.SetData(Index: longint; AValue: TVector3D);
  1555. begin
  1556.   with TVector3D(Ptr(Longint(FData)+(Index*SizeOf(TVector3D)))^) do
  1557.   begin
  1558.     x := AValue.x;
  1559.     y := AValue.y;
  1560.     z := AValue.z;
  1561.   end;
  1562. end;
  1563.  
  1564. function TDataSet3D.GetData(Index: longint): TVector3D;
  1565. begin
  1566.   with TVector3D(Ptr(Longint(FData)+(Index*SizeOf(TVector3D)))^) do
  1567.   begin
  1568.     Result.x := x;
  1569.     Result.y := y;
  1570.     Result.z := z;
  1571.   end;
  1572. end;
  1573.  
  1574. procedure TDataSet3D.SetCount(AValue: longint);
  1575. begin
  1576.   if AValue <> FCount then
  1577.   begin
  1578.     FCount := AValue;
  1579.     ReAllocMem(FData,AValue*SizeOf(TVector3D));
  1580.   end;
  1581. end;
  1582.  
  1583. constructor TDataSet3D.Create(ACount: longint);
  1584. begin
  1585.   inherited Create;
  1586.   FCount := ACount;
  1587.   GetMem(FData,ACount*SizeOf(TVector3D));
  1588. end;
  1589.  
  1590. destructor TDataSet3D.Destroy;
  1591. begin
  1592.   FreeMem(FData,FCount*SizeOf(TVector3D));
  1593.   inherited Destroy;
  1594. end;
  1595.  
  1596. end.
  1597.